{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4-二维的PCA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "sns.set(context=\"notebook\", style=\"white\")\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import scipy.io as sio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# load data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def get_X(df):\n",
    "    \"\"\"\n",
    "    use concat to add intersect feature to avoid side effect\n",
    "    not efficient for big dataset though\n",
    "    \"\"\"\n",
    "    ones = pd.DataFrame({'ones': np.ones(len(df))})\n",
    "    data = pd.concat([ones, df], axis=1)  # column concat\n",
    "    return data.iloc[:, :-1].as_matrix()  # this return ndarray, not matrix\n",
    "\n",
    "\n",
    "def get_y(df):\n",
    "    '''assume the last column is the target'''\n",
    "    return np.array(df.iloc[:, -1])\n",
    "\n",
    "\n",
    "def normalize_feature(df):\n",
    "    \"\"\"Applies function along input axis(default 0) of DataFrame.\"\"\"\n",
    "    return df.apply(lambda column: (column - column.mean()) / column.std())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(50, 2)\n"
     ]
    }
   ],
   "source": [
    "mat = sio.loadmat('./data/ex7data1.mat')\n",
    "X = mat.get('X')\n",
    "\n",
    "# visualize raw data\n",
    "print(X.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0xbcf0128>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.lmplot('X1', 'X2', \n",
    "           data=pd.DataFrame(X, columns=['X1', 'X2']),\n",
    "           fit_reg=False)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# normalize data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# support functions ---------------------------------------\n",
    "def plot_n_image(X, n):\n",
    "    \"\"\" plot first n images\n",
    "    n has to be a square number\n",
    "    \"\"\"\n",
    "    pic_size = int(np.sqrt(X.shape[1]))\n",
    "    grid_size = int(np.sqrt(n))\n",
    "\n",
    "    first_n_images = X[:n, :]\n",
    "\n",
    "    fig, ax_array = plt.subplots(nrows=grid_size, ncols=grid_size,\n",
    "                                    sharey=True, sharex=True, figsize=(8, 8))\n",
    "\n",
    "    for r in range(grid_size):\n",
    "        for c in range(grid_size):\n",
    "            ax_array[r, c].imshow(first_n_images[grid_size * r + c].reshape((pic_size, pic_size)))\n",
    "            plt.xticks(np.array([]))\n",
    "            plt.yticks(np.array([]))\n",
    "\n",
    "\n",
    "# PCA functions ---------------------------------------\n",
    "def covariance_matrix(X):\n",
    "    \"\"\"\n",
    "    Args:\n",
    "        X (ndarray) (m, n)\n",
    "    Return:\n",
    "        cov_mat (ndarray) (n, n):\n",
    "            covariance matrix of X\n",
    "    \"\"\"\n",
    "    m = X.shape[0]\n",
    "\n",
    "    return (X.T @ X) / m\n",
    "\n",
    "\n",
    "def normalize(X):\n",
    "    \"\"\"\n",
    "        for each column, X-mean / std\n",
    "    \"\"\"\n",
    "    X_copy = X.copy()\n",
    "    m, n = X_copy.shape\n",
    "\n",
    "    for col in range(n):\n",
    "        X_copy[:, col] = (X_copy[:, col] - X_copy[:, col].mean()) / X_copy[:, col].std()\n",
    "\n",
    "    return X_copy\n",
    "\n",
    "\n",
    "def pca(X):\n",
    "    \"\"\"\n",
    "    http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.svd.html\n",
    "    Args:\n",
    "        X ndarray(m, n)\n",
    "    Returns:\n",
    "        U ndarray(n, n): principle components\n",
    "    \"\"\"\n",
    "    # 1. normalize data\n",
    "    X_norm = normalize(X)\n",
    "\n",
    "    # 2. calculate covariance matrix\n",
    "    Sigma = covariance_matrix(X_norm)  # (n, n)\n",
    "\n",
    "    # 3. do singular value decomposition\n",
    "    # remeber, we feed cov matrix in SVD, since the cov matrix is symmetry\n",
    "    # left sigular vector and right singular vector is the same, which means\n",
    "    # U is V, so we could use either one to do dim reduction\n",
    "    U, S, V = np.linalg.svd(Sigma)  # U: principle components (n, n)\n",
    "\n",
    "    return U, S, V\n",
    "\n",
    "\n",
    "def project_data(X, U, k):\n",
    "    \"\"\"\n",
    "    Args:\n",
    "        U (ndarray) (n, n)\n",
    "    Return:\n",
    "        projected X (n dim) at k dim\n",
    "    \"\"\"\n",
    "    m, n = X.shape\n",
    "\n",
    "    if k > n:\n",
    "        raise ValueError('k should be lower dimension of n')\n",
    "\n",
    "    return X @ U[:, :k]\n",
    "\n",
    "\n",
    "def recover_data(Z, U):\n",
    "    m, n = Z.shape\n",
    "\n",
    "    if n >= U.shape[0]:\n",
    "        raise ValueError('Z dimension is >= U, you should recover from lower dimension to higher')\n",
    "\n",
    "    return Z @ U[:, :n].T\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\ns9UbWeUujItuDgIXSFgxfvqHeuiM76y7OQhcIEHFajVaSL2Rmq9/qOECCSpWq9GN1hup+fqJFS6Q\noGL99L/ReiM1Xz8RuECCitlqdCP1Rmq+fqKkACTIl4NjQj1oPHYELpAgXw7K9iX4MR0lBSBhPhwc\nw4lhfiJwgUj5EPyYjpICABghcAHACIELAEYIXAAwQuACgBECFwCMELgAYITABQAjeQO3p6dH3/ve\n9/T1r39dL7zwgq5evTr113bu3GkyOQCISd6dZi0tLXrggQe0bt06Pf/883rsscfU3t6usrIy/etf\n/7KcI5BaHCIel7yBOzAwoG3btkmS2tvb1dTUpObmZv3yl780mxzgu8lAPPfxgD4dHVdFeYn+67ab\nEgnGYr09Is1c38DylhRKS0v1wQcfSJIWLVqkp556ShcvXtSePXumlReAtJoMxH92D6hvYESXhzPq\nHxjRP7v/ncjbFYr19oi08uEtGHkDt6WlRTt37tSf/vQnSVJ5ebna29vV19enrq4uswmmwZnO8/r5\n4b9q17Nv6OeH/8prUAIxGYiDw5lp44PDo5IKD0YOEU+WDzewvCWF3/72tzp+/LgqKiqmxpYtW6ad\nO3fqz3/+s8XcUoGfjeGaDMTRsfFp45OfCw3GYr49Io18uIHlXeF+8Ytf1LZt2/SPf/xDkjQ+Pq7n\nn39eO3fuVFtbm9kEY+fDXRcLM/lWhfKy6X+MJj8XGowcIp4sH96CkXeF++1vf1t33323mpub9dWv\nflV/+ctfVFFRod///vdatWqV2QRj58NdFwuzqa5Gh1/7u5ZXVqj/0sjU+PLKckmFByOHiCdr8t/X\n9SxvYLMeQH7XXXfp0UcfVVtbm1asWKFXXnmloLAdHx/X3r171dnZqYqKCu3bt0+33377gv9+MeBn\nY7iuDcRFiy4pM3p1qkshqWDkEPHk+HADyxu4Fy9e1JNPPqmenh798Y9/1OnTp/XII4/oRz/6kR54\n4IEFXezEiRPKZDI6cuSIOjo61NbWpvb29gVPPgY+3HWxcARiWFz/+8obuF/72te0detWPffccyov\nL9eaNWt0991364knntAbb7yhp59++oYvdvr0ad13332SJlbPZ8+eXfjMI+HDXReAjbyB+4tf/EJ1\ndXXTxtasWaPf/e53+tnPfragiw0NDamqqmrqc2lpqcbGxlRWlu5Xq7m+68It1834sJM36a4P20mL\n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\nRK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x6499828>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "X_norm = normalize(X)\n",
    "\n",
    "sns.lmplot('X1', 'X2', \n",
    "           data=pd.DataFrame(X_norm, columns=['X1', 'X2']),\n",
    "           fit_reg=False)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# covariance matrix $\\Sigma$\n",
    "<img style=\"float: left;\" src=\"../img/cov_mat.png\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "this is biased sample covariance matrix, for unbiased version, you need to divide it by $m-1$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.        ,  0.73553038],\n",
       "       [ 0.73553038,  1.        ]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Sigma =covariance_matrix(X_norm)  # capital greek Sigma\n",
    "Sigma  # (n, n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PCA\n",
    "http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.svd.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "U, S, V = pca(X_norm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.70710678, -0.70710678],\n",
       "       [-0.70710678,  0.70710678]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "U"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.70710678, -0.70710678])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u1 = U[0]\n",
    "u1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# project data to lower dimension"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.49631261],\n",
       "       [-0.92218067],\n",
       "       [ 1.22439232],\n",
       "       [ 1.64386173],\n",
       "       [ 1.2732206 ],\n",
       "       [-0.97681976],\n",
       "       [ 1.26881187],\n",
       "       [-2.34148278],\n",
       "       [-0.02999141],\n",
       "       [-0.78171789]])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# show top 10 projected data\n",
    "Z = project_data(X_norm, U, 1)\n",
    "Z[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "http://stackoverflow.com/a/23973562/3943702"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAswAAAETCAYAAAAiUVB9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3X1c1GW+//E3ci+ohKVWRGlpZys9Kj3c2vRUaouZppsi\nqIuHdFvz+DBNwxuOdyfzbvMmI0Wj3WrJQiBTfKzHrbRdy8x7+enpRKttGoYi4k2AOgMzvz88TCLD\ncDcz35nh9Xw8ethc3+98rw+Dfucz13yu6/KzWq1WAQAAALCrhdEBAAAAAJ6MhBkAAABwgIQZAAAA\ncICEGQAAAHCAhBkAAABwgIQZAAAAcICEGU3ywQcf6Omnn9bAgQP11FNPKTk5WT/++GOt5z/33HM6\nduyYw2uuWrVKmzZtanRMiYmJ2rZtW53nDRo0SHv27NGZM2eUkJDQ6P6ayuj+AaA+jhw5oiFDhlT7\n76GHHtITTzxR53NffvllpaamSqrf+4ArGd0/vFOA0QHAey1dulTffPON1q1bp1tvvVUWi0W5ubmK\nj49Xdna2OnToUOM56enpdV538uTJrgi3Vu3bt1dmZqZb+/Sk/gGgPrp27arNmzfbHh8/flyjRo3S\njBkzGnSd+rwPuJLR/cM7kTCjUU6fPq3MzEz97W9/U5s2bSRJLVq00NChQ3X06FGtW7dO8+bNU9++\nfdWtWzfl5+dr6tSpWrx4sVatWqWuXbvqzTffVE5OjsLCwvTggw9q+/bt2rFjh2bOnKnOnTtr3Lhx\n6tq1q37/+99r165dKioq0pgxY5SUlKTy8nLNnz9f33//vS5evKiwsDAtW7ZMnTp1qjXmY8eOKSUl\nRZcvX1anTp1UXl4uSSooKNDgwYN16NAhpaam6uTJk/rhhx9UVFSkbt266ZFHHtGmTZtUUFCg5ORk\nDRo0SJKUlpamjz/+WBaLRbfffrvmzZun9u3bKzExUd27d9fBgwdVWFiomJgYLV26VBaLRQsWLNDB\ngwcVGBioqKgoLV68WOfPn7f1bzabtWTJEu3evVv+/v7q1q2bZs2apfDwcPXt21e/+c1vtHv3bhUW\nFurJJ5/U9OnTXf/LBoAbnD9/XuPHj9fYsWPVv3//GsdLS0v1n//5n/rmm2/Url07+fv7KyYmRpLU\nt29frVq1SuXl5VqxYoXatWunf/zjHwoNDdWkSZOUkZGhf/7zn/r1r3+tlJQUSdKOHTuUlpYms9ms\nkJAQzZgxQz169FBqaqpOnTqls2fP6tSpU4qMjNTKlSvVvn17vf/++8rMzFRgYKCCg4P18ssv6557\n7rH137VrV23YsEEZGRlq0aKFbr75Zs2ZM0cdO3bUzJkzFR4ervz8fJ0+fVqdOnXSihUrFBYW5tbX\nGZ6Dkgw0Sl5enjp16mRLlq/3q1/9SgcOHLA97ty5s/77v/+72td2n3/+uTZu3KicnBxt3LhRZWVl\ndvsxmUy66aablJmZqddff13Lly/X1atXtXPnTrVu3VpZWVn661//qgceeEDr1693GPNLL72kuLg4\nbdmyRWPGjKm1dOTAgQNKT0/X1q1b9eWXX+r48eNav3695syZY/tKcdOmTfr222+VnZ2tzZs369FH\nH9Xs2bNt1zh58qQyMjKUm5urr776Snv37tXhw4e1d+9e5ebmauPGjbrjjjuUn59fre+0tDQVFRVp\n8+bN2rx5sywWi/7whz/YjpeXl9veBN577z398MMPDn9mAHC2iooKTZ48Wd27d9f48ePtnvP6668r\nJCRE27Zt06pVq/TPf/7T7nlHjhzRhAkTtG3bNrVt21Zvvvmm1q1bp40bN+r999/XmTNn9P3332vl\nypV68803tWnTJi1YsECTJk2yDXrs379fq1at0rZt29S6dWtt2LBBlZWVWrRokd566y19+OGHGjFi\nRLX3JUnavXu33nrrLf35z39Wbm6uBg0apIkTJ6pqA+SjR4/qj3/8o7Zu3aqioqJ6lfrBdzHCjEar\nqKiw224ymeTn52d7/OCDD9Y45+9//7sGDBig1q1bS5JGjx6tr776yu71+vXrJ0m6//77ZTKZVF5e\nrgEDBuiOO+5QRkaGTpw4ob1796pHjx61xnr+/Hnl5+dr6NChkqSYmBh17tzZ7rm/+tWv1KpVK0lS\nu3bt1KdPH0lSdHS0Lly4IEn67LPPdOTIEQ0bNkySZLFYdPnyZds1Hn/8cbVo0ULh4eG68847dfHi\nRT388MPy9/dXXFycevfurdjYWHXr1k0FBQW25+3cuVMvvviiAgMDJV2rx544cWKN16J9+/Zq27at\nLl68qDvuuKPWnxswSl5enpYtW6aMjAynPP/rr7/W+PHjddddd0mSRo4cqYEDBzorXDTAwoULdeXK\nFS1cuLDWc3bv3q2UlBT5+fkpMjKy1jrnqKgo3XfffZKu3WNbtWqloKAgRUZGKiwsTBcvXtS+fftU\n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\ncICEGQAAAHCAhBkAAABwwKNXyaisrJQknT592uBIAKBhqu5bVfex5qAp92xzeYkKCgrq3d6Uazb2\nujc+p+rxjX86el59+jWXl0hStedc/7i+P0dt8dUVb13XcXRObfE39ndo73q19VtX/HUdr+3325g4\nG/paO/o7UnXdqms39OczipFxNabvuu7Zflar1drkyFxk//79Gj16tNFhAECjrV+/Xg8++KDRYbgF\n92wA3q62e7ZHJ8xXrlzR0aNHdcstt8jf39/ocACg3iorK3X27Fk98MADCgkJMToct+CeDcBb1XXP\n9uiEGQAAADAak/4AAAAAB0iYAQAAAAdImAEAAAAHSJgBAAAAB0iYAQAAAAdImJ3kp59+0vPPP6/f\n/va3io+P16FDh4wOySN88sknmjZtmtFhGMJisWju3LmKj49XYmKiTpw4YXRIHiEvL0+JiYlGhwEf\n5Gv3YW+8f/rafc/b71dms1nJyckaNWqUhg8fru3btxsdUqNUVlZq1qxZSkhI0MiRI/Xtt9+6PQaP\n3unPm7z99tt66KGHlJSUpO+++07Tpk3TRx99ZHRYhnrllVf0xRdf6Be/+IXRoRji008/lclk0oYN\nG3T48GEtWbJEaWlpRodlqPT0dOXm5io0NNToUOCDfOk+7K33T1+67/nC/So3N1cRERF69dVXdeHC\nBQ0dOlT9+vUzOqwG++yzzyRJmZmZ2rNnj1auXOn2v1eMMDtJUlKSEhISJF37JBQcHGxwRMbr2bOn\n5s+fb3QYhjlw4ID69OkjSerevbuOHj1qcETGi46OVmpqqtFhwEf50n3YW++fvnTf84X71YABAzR5\n8mRJktVq9doNhfr3768FCxZIkn788Ue1bt3a7TEwwtwI2dnZevfdd6u1LVq0SN26ddPZs2eVnJys\nlJQUg6Jzv9pej4EDB2rPnj0GRWW80tJShYeH2x77+/uroqJCAQHN959dbGysCgoKjA4DPsBX7sO+\ndv/0pfueL9yvwsLCJF37vbzwwguaMmWKwRE1XkBAgGbMmKFPPvlEr7/+uvv7d3uPPiAuLk5xcXE1\n2vPz8zV16lRNnz5dvXr1MiAyY9T2ejR34eHhKisrsz22WCxe+aYBeCJfuQ/72v2T+57nKSws1MSJ\nEzVq1CgNHjzY6HCaZOnSpXrppZc0YsQI/eUvf1HLli3d1jclGU5y7NgxTZ48WcuXL9ejjz5qdDjw\nAD179tTOnTslSYcPH1aXLl0MjgjwbdyHjcd9z7MUFxdr7NixSk5O1vDhw40Op9E2bdqkdevWSZJC\nQ0Pl5+enFi3cm8Lysc9Jli9fLpPJpIULF0q69inbWyc6wDmeeOIJ7dq1SwkJCbJarVq0aJHRIQE+\njfuw8bjveZa1a9fq0qVLWrNmjdasWSPp2mTGkJAQgyNrmF//+teaNWuWRo8erYqKCqWkpLj9Z/Cz\nWq1Wt/YIAAAAeBFKMgAAAAAHSJgBAAAAB0iYAQAAAAdImAEAAAAHSJgBAAAAB0iY4fP27Nmj3r17\n69y5c7a2P/7xj5o0aZLt8apVq7x+C1QA8EX79+/XkCFDqv33i1/8Qps3bzY6NDQjLCuHZmHp0qX6\n/vvvlZaWpsOHD2v69OnKycmRn5+fFi9erL/85S/63e9+Vy2JBgB4nnfeeUebNm3Shg0bFBwcbHQ4\naCZImNEsmEwmxcXFadiwYXrvvfe0dOlS9ejRQ5s2bVJRUZHKy8vl7+9PwgwAHmz//v2aOHGisrOz\nFR0dbXQ4aEbY6Q/NQlBQkJYtW6YhQ4bo97//vXr06CFJGjp0qCRRjgEAHu7cuXOaOnWqFi5cSLIM\nt6OGGc3GwYMHddNNN2n37t2qqKgwOhwAQD1ZLBZNmzZNTz31lPr37290OGiGSJjRLBw7dkypqanK\nzMxUUFCQ0tLSjA4JAFBPb7zxhsxms6ZNm2Z0KGimSJjh865evaoXX3xRycnJuuOOO7RkyRK99957\nOnz4sNGhAQDqsGvXLmVnZ2vlypUKCKCSFMbgbx583qJFi9SlSxcNGTJEknT77bdr1qxZSk5O1qZN\nmxQWFmZwhACA2qxbt06VlZV67rnnqrUnJCRo5MiRBkWF5oZVMgAAAAAHKMkAAAAAHCBhBgAAABwg\nYQYAAAAcIGEGAAAAHCBhBgAAABwgYQYAAAAcIGEGAAAAHPj/32i0pLM+DWcAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x64efcc0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 4))\n",
    "\n",
    "sns.regplot('X1', 'X2', \n",
    "           data=pd.DataFrame(X_norm, columns=['X1', 'X2']),\n",
    "           fit_reg=False,\n",
    "           ax=ax1)\n",
    "ax1.set_title('Original dimension')\n",
    "\n",
    "sns.rugplot(Z, ax=ax2)\n",
    "ax2.set_xlabel('Z')\n",
    "ax2.set_title('Z dimension')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# recover data to original dimension\n",
    "Of course, there would be inevitable information loss if you boost data from lower to higher dimension"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsEAAAETCAYAAADXr9vNAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xtc1GXaP/DPHAVmUBdNqTVcNXVT84D+TFMzPKSh5ikE\nLUzTrdxqM13MLF3XPGBlaZas1bNaVB6wTH1e1ZMgrU9qmhIq+Yh5SNIYERBlBmUO3/v3B83IwMAA\nzvCdw+f9elXM/Z3DNdgNl/fc93UphBACRERERERBRCl3AEREREREjY1JMBEREREFHSbBRERERBR0\nmAQTERERUdBhEkxEREREQYdJMBEREREFHSbBMjl+/DjGjh3r9E+/fv0wfPhwt49dsmQJ1q5dCwD4\ny1/+gtOnT3s73BrJ/fpEruzYsQMPP/wwxo4di4SEBBw/fhwAsHbtWvTr188x50aNGoWnn34a586d\n81osGRkZWLp0aYMf/8477yA9PR0AsGbNGnzxxRceictms2HWrFkYMWIEPv74Y488Z22q/rwbMmQI\nOnfuDIPB4PXXJv+0adMmPPzww4iNjcWoUaOQlJSE3377rcb71+X30a3OocTERHz99ddu7zd69Ggc\nPHgQly5dQkJCQoNf71bJ/fo+T5BPOH36tOjbt6/YvXu32/v+85//FG+//XYjREXkf86cOSMGDBgg\nLl26JIQQ4ttvvxWDBw8WQgjx9ttvi3/+859O99++fbu4//77RWlpaWOHWiePPfaY+Oqrrzz+vBcv\nXhTdunUTVqvV48/tjslkEuPHjxcrVqxo9Ncm/5CcnCymTZsmfvvtNyGEEDabTWzfvl0MHDhQ5Ofn\nyxZXXefjqFGjxPfff98IEdGtUMudhBNw5coVPPXUU3jiiScwbNiwateNRiNefvllnDx5Eq1atYJK\npULv3r0BAEOGDMGaNWtQVlaGN998E61atcLPP/+M0NBQPPfcc0hNTcW5c+fw4IMPYsGCBQCAPXv2\nICUlBRaLBSEhIXjxxRfRq1cvrF27FhcvXsTly5dx8eJFRERE4K233kLr1q3x6aefYvPmzdBoNGjS\npAmWLFmCu+66y/H699xzD7Zs2YLU1FQolUq0bNkSCxcuRLt27TB//nzo9Xrk5ubCYDCgffv2ePPN\nN6HT6Rr1+0zBQavVYunSpWjVqhUAoFu3bigsLITZbHZ5/3HjxmHnzp3YtWsXJk+e7HRt/vz5UCgU\nOHPmDIqLizFgwAC88sor0Gg06NatG4YOHYqTJ0/ijTfeQHl5OV577TVcv34dGo0Gs2fPxv3334/P\nP/8c//M//4P169ejtLQUy5Ytw6lTp2CxWNC/f3/MmzcParUaR48exdKlSx2PnzdvHs6ePYucnBy8\n9tprUKlUyMjIQMeOHTFjxgwcPny4xtfbvXs3lEolzp8/D41Gg5UrV6JTp06O92U0GjFz5kxYrVZM\nmDABa9euRWxsbJ3fzzfffIMbN27g4sWLuP322/Hoo4/i448/xi+//ILp06fjiSeeqPHPRwiBefPm\noUWLFpg3b54H/sQp0BgMBmzevBnffvstmjVrBgBQKpUYN24ccnJysH79evzjH//AkCFD0L17d+Tm\n5mLOnDlYsWKF4/fRe++9h23btkGn06FPnz7IyMjAnj17MH/+fMccuueee/Dkk09i3759KCgowNSp\nUzFt2jSUlZVh8eLF+OWXX3D16lXodDq88cYbaN++fY0xnz59GgsWLMD169fRvn17lJWVAQAuXLiA\nMWPG4Mcff8TatWuRl5eHX3/9FQUFBejevTsGDBiAL774AhcuXEBSUhJGjx4NAEhJScE333wDSZLw\nxz/+Ef/4xz/QunVrJCYmomfPnsjKykJ+fj569+6NlStXQpIkvPrqq8jKyoJGo0GbNm2wYsUKXLly\nxfH6FosFycnJOHDgAFQqFbp3746XXnoJer0eQ4YMwfjx43HgwAHk5+fjoYceCo75KXcWHuwsFotI\nTEwUc+fOrfE+y5YtE/PmzROSJImioiJx//33O1aCY2JixLFjx8T3338v7r77bvHTTz8JIYSYMWOG\niI+PF+Xl5aKoqEh07dpVGAwGce7cOTF69GhRXFwshBDi1KlTYsCAAcJkMom3335bDB061LEi9tRT\nT4k1a9YIq9Uqunbt6lhZ2759u9i8ebPT6+/fv18MGzZMFBUVCSGE+Oyzz8RDDz0kJEkSL774oiMW\ns9ksxo0bJ7Zt2+adbyhRJZIkiblz54rnnntOCOF6JViIilWnxYsXVxt/8cUXxbhx44TRaBTl5eXi\n0UcfFampqUIIITp16iS2b98uhBCiuLhY9O/fX2RnZwshKuZV3759RV5envjss8/Ek08+KYQQYv78\n+eKjjz4SQghhtVrF3//+d/Hee+8Js9ksBgwYIDIzM4UQQhw/flyMHj1a2Gw2p5WnF198UXzwwQdu\nX693796O1bIlS5aIefPmVXtvv/76q+jZs6fjdn3eT+/evcVvv/0mbDabiI2NFc8995yw2Wzi//7v\n/8Q999wjbDZbjX8mb731loiNjfXZlXeS39dffy0mTJjg8lpGRoYYM2aMEKLi988777zjuGb/fbR3\n714xYsQIcfXqVSFJknjppZdETEyMEOLmHBKi4v95+3w+fvy46Natm7hx44b46quvxKuvvup43oUL\nF4olS5YIIWpeCR47dqzYunWrEEKIw4cPi86dO4vvv//eaZ69/fbbIiYmRly7dk1cv35d/L//9/8c\nn4bs3r1bPPjgg0KIit+xs2fPFhaLRQghxObNm8XMmTMdr/+3v/1N2Gw2UVpaKgYOHCgOHDggfvjh\nBzFy5EghSZIQQojXXntNHDlyxOn116xZI5599llhNpuFzWYT8+fPFwsXLnR875KTk4UQQhgMBnHP\nPfeIvLy8Ov15+TOuBMts2bJluHHjBpYtW1bjfQ4cOIAFCxZAoVAgIiKixn3Dbdq0QZcuXQAAUVFR\nCA8Ph1arRUREBHQ6Ha5evYoffvgBBQUFmDZtmuNxCoUCeXl5AIC+fftCr9cDALp06YKrV69CpVJh\n5MiRSEhIwAMPPIABAwZgzJgxTq/9v//7v4iNjUVERAQAYMKECVi2bBkuXLgAABg0aBC0Wi0AoFOn\nTrh69WoDvltEdVdWVob58+fDYDDggw8+qPW+CoUCISEhLq+NHz/e8anF2LFjkZGRgcceewwA0KdP\nHwDAsWPHEBUVhR49egAAOnbsiOjoaBw6dAgKhcLxXN9++y2OHz+Obdu2AQBu3LgBADh16hSUSiUe\neOABABWr17t27aoxXnev17VrV0RGRgKomMe7d++u9f3b1fX93HPPPbj99tsBVPzcGThwIJRKJe68\n806Ul5fj+vXrLj/p+eqrr7Bp0yakpaU5fs4QuWK1Wl2Om81mpzll/3+2sv/85z8YOXIkmjZtCgB4\n9NFH8f3337t8vqFDhwIAunbtCrPZjLKyMowcORJ33nknUlNTcf78eRw6dAi9evWqMdYrV64gNzcX\n48aNAwD07t0bHTt2dHnf++67D+Hh4QCAVq1aYdCgQQAqfmeXlJQAADIzM3H8+HFMnDgRACBJEq5f\nv+54jpiYGCiVSuj1erRt2xZXr15F//79oVKpEBcXh4EDB2LEiBHo3r2743cwAOzduxcvvPACNBoN\n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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x651a780>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "X_recover = recover_data(Z, U)\n",
    "\n",
    "fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(12, 4))\n",
    "\n",
    "sns.rugplot(Z, ax=ax1)\n",
    "ax1.set_title('Z dimension')\n",
    "ax1.set_xlabel('Z')\n",
    "\n",
    "sns.regplot('X1', 'X2', \n",
    "           data=pd.DataFrame(X_recover, columns=['X1', 'X2']),\n",
    "           fit_reg=False,\n",
    "           ax=ax2)\n",
    "ax2.set_title(\"2D projection from Z\")\n",
    "\n",
    "sns.regplot('X1', 'X2', \n",
    "           data=pd.DataFrame(X_norm, columns=['X1', 'X2']),\n",
    "           fit_reg=False,\n",
    "           ax=ax3)\n",
    "ax3.set_title('Original dimension')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### the projection from `(X1, X2)` to `Z` could be visualized like this"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img style=\"float: central;\" src=\"../img/pca_projection.png\">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
